package com.platform.usercenter.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.platform.common.core.constant.Constants;
import com.platform.common.core.constant.UserConstants;
import com.platform.common.core.domain.entity.SysRole;
import com.platform.common.core.domain.entity.SysUser;
import com.platform.common.core.enums.MenuEndPointEnum;
import com.platform.common.core.exception.ServiceException;
import com.platform.common.core.utils.JwtUtils;
import com.platform.common.core.utils.StringUtils;
import com.platform.common.redis.service.RedisService;
import com.platform.common.security.utils.SecurityUtils;
import com.platform.constants.SysUserConstants;
import com.platform.usercenter.config.ConfigConstants;
import com.platform.usercenter.constants.UserCenterConstant;
import com.platform.usercenter.domain.SysAppScene;
import com.platform.usercenter.domain.SysMenuTreeDTO;
import com.platform.usercenter.domain.SysOrganizationPermission;
import com.platform.usercenter.domain.dto.SelectOptionDTO;
import com.platform.usercenter.domain.dto.SysMenuPermissionDTO;
import com.platform.usercenter.domain.query.SysMenuQuery;
import com.platform.usercenter.domain.vo.MetaVo;
import com.platform.usercenter.domain.vo.RouterVo;
import com.platform.usercenter.domain.vo.SysMenuPermissionVO;
import com.platform.usercenter.domain.vo.TreeSelect;
import com.platform.usercenter.enums.MenuStatus;
import com.platform.usercenter.mapper.SysMenuMapper;
import com.platform.usercenter.mapper.SysRoleMapper;
import com.platform.usercenter.mapper.SysRoleMenuMapper;
import com.platform.usercenter.service.ISysAppSceneService;
import com.platform.usercenter.service.ISysMenuService;
import com.platform.usercenter.service.ISysOrganizationPermissionService;
import com.platform.usercenter.service.ISysUserCommonService;
import com.platform.usercenter.utils.TreeAdapterUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 菜单 业务层处理
 *
 * @author
 */
@Service
@Slf4j
public class SysMenuServiceImpl implements ISysMenuService {
    public static final String PREMISSION_STRING = "perms[\"{0}\"]";

    @Resource
    private SysMenuMapper menuMapper;

    @Resource
    private SysRoleMapper roleMapper;

    @Resource
    private SysRoleMenuMapper roleMenuMapper;

    @Resource
    private ConfigConstants configConstants;


    @Resource
    private ISysUserCommonService sysUserCommonService;

    @Resource
    private ISysOrganizationPermissionService organizationPermissionService;

    @Resource
    private ISysAppSceneService sysAppSceneService;

    /**
     * 根据用户查询系统菜单列表
     *
     * @param userId 用户ID
     * @return 菜单列表
     */
    @Override
    public List<SysMenuTreeDTO> selectMenuList(Long userId, Long deptId) {
        return selectMenuList(new SysMenuQuery(), userId, deptId);
    }

    @Override
    public List<SysMenuTreeDTO> selectMenuListCheckApp(SysMenuQuery menuQuery) {
        return menuMapper.selectMenuList(menuQuery);
    }


    /**
     * 查询系统菜单列表
     *
     * @param menuQuery 菜单信息
     * @return 菜单列表
     */
    @Override
    public List<SysMenuTreeDTO> selectMenuList(SysMenuQuery menuQuery, Long userId, Long orgId) {
        List<SysMenuTreeDTO> menuList;
        // 管理员显示所有菜单信息
        if (sysUserCommonService.isAdmin(userId)) {
            menuList = menuMapper.selectMenuList(menuQuery);
        } else {
            menuQuery.setOrgId(orgId);
            menuQuery.setUserId(userId);
            menuList = menuMapper.selectMenuListByUserId(menuQuery);
        }
        return TreeAdapterUtil.buildTree(menuList, SysMenuTreeDTO.class, null);
    }

    /**
     * 查询系统菜单列表
     *
     * @param menuQuery 菜单信息
     * @return 菜单列表
     */
    @Override
    public List<SysMenuTreeDTO> selectMenuListByGranded(SysMenuQuery menuQuery, Long userId, Long orgId) {
        List<SysMenuTreeDTO> menuList = new ArrayList<>();
        // 查询全部应用
        Map<Long, String> appNameMap = new HashMap<>();
        SysAppScene appSceneQuery = new SysAppScene();
        appSceneQuery.setIsDelete(SysUserConstants.N);
        List<SysAppScene> appScenes = sysAppSceneService.selectSysAppSceneList(appSceneQuery);
        if (CollectionUtil.isNotEmpty(appScenes)) {
            appNameMap = appScenes.stream().collect(Collectors.toMap(SysAppScene::getAppSceneId, item -> item.getSceneName()));
        }

        // 管理员显示所有菜单信息
        if (sysUserCommonService.isAdmin(userId)) {
            menuList = menuMapper.selectMenuList(menuQuery);
        } else {
            // 查询该组织下全部应用
            List<SysOrganizationPermission> appIds = organizationPermissionService.selectSysOrganizationPermissionListByApp(orgId);
            if (CollectionUtil.isNotEmpty(appIds)) {
                // 获取该组织下的分级管理员角色
                SysRole role = roleMapper.getGrandedRole(orgId);
                if (ObjectUtil.isNotEmpty(role)) {
                    // 查询该组织下分级管理员配置的菜单
                    menuQuery.setOrgId(orgId);
                    menuQuery.setUserId(userId);
                    menuQuery.setRoleId(role.getRoleId());
                    List<SysMenuTreeDTO> userMenus = menuMapper.selectMenuListByUserId(menuQuery);
                    if (CollectionUtil.isNotEmpty(userMenus)) {
                        // 过滤出目录和按钮
                        List<SysMenuTreeDTO> notCmenuAll = userMenus.stream().filter(item -> !"C".equals(item.getMenuType())).collect(Collectors.toList());
                        if (CollectionUtil.isNotEmpty(notCmenuAll)) {
                            menuList.addAll(notCmenuAll);
                        }
                        List<SysMenuTreeDTO> isCmenuAll = userMenus.stream().filter(item -> "C".equals(item.getMenuType())).collect(Collectors.toList());
                        if (CollectionUtil.isNotEmpty(isCmenuAll)) {
                            // 过滤出该组织下的全部应用菜单
                            List<Long> appSceneIds = appIds.stream().map(SysOrganizationPermission::getAppSceneId).collect(Collectors.toList());
                            isCmenuAll = isCmenuAll.stream().filter(item -> appSceneIds.contains(item.getAppSceneId())).collect(Collectors.toList());
                            if (CollectionUtil.isNotEmpty(isCmenuAll)) {
                                menuList.addAll(isCmenuAll);
                            }
                        }
                    }
                }
            }
        }
        if (CollectionUtil.isNotEmpty(menuList)) {
            for (SysMenuTreeDTO sysMenuVO : menuList) {
                if (ObjectUtil.isNotEmpty(sysMenuVO.getAppSceneId())) {
                    String appName = appNameMap.get(sysMenuVO.getAppSceneId());
                    if (StringUtils.isNotEmpty(appName)) {
                        sysMenuVO.setSceneName(appName);
                    }
                }
            }
        }
        return filterMenuTree(TreeAdapterUtil.buildTree(menuList, SysMenuTreeDTO.class, null));
    }

    /**
     * 校验目录下是否存在菜单，若不存在菜单则剔除当前层级目录
     *
     * @param menuTree
     * @return
     */
    public static List<SysMenuTreeDTO> filterMenuTree(List<SysMenuTreeDTO> menuTree) {
        List<SysMenuTreeDTO> filteredTree = new ArrayList<>();
        for (SysMenuTreeDTO node : menuTree) {
            if (hasButtonInSubtree(node)) {
                // 如果当前节点及其子树包含按钮类型的菜单，则保留该节点并递归过滤其子女节点
                SysMenuTreeDTO filteredNode = new SysMenuTreeDTO();
                filteredNode.setAppSceneId(node.getAppSceneId());
                filteredNode.setMenuId(node.getMenuId());
                filteredNode.setMenuType(node.getMenuType());
                filteredNode.setMenuName(node.getMenuName());
                filteredNode.setSceneName(node.getSceneName());
                if (CollectionUtil.isNotEmpty(node.getChildren()) && !node.getMenuType().equals(SysUserConstants.MENU_TYPE_C)) {
                    filteredNode.setChildren(filterMenuTree(node.getChildren()));
                } else if (CollectionUtil.isNotEmpty(node.getChildren()) && node.getMenuType().equals(SysUserConstants.MENU_TYPE_C)) {
                    filteredNode.setChildren(node.getChildren());
                }
                filteredTree.add(filteredNode);
            }
        }
        return filteredTree;
    }


    // 用于判断当前节点及其子树是否包含按钮类型的菜单
    public static boolean hasButtonInSubtree(SysMenuTreeDTO node) {
        if (node.getMenuType().equals(SysUserConstants.MENU_TYPE_C)) {
            return true;
        }
        if (CollectionUtil.isNotEmpty(node.getChildren())) {
            for (SysMenuTreeDTO child : node.getChildren()) {
                if (hasButtonInSubtree(child)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 根据用户ID查询权限
     *
     * @param userId 用户ID
     * @return 权限列表
     */
    @Override
    public Set<String> selectMenuPermsByUserId(Long userId) {
        List<String> perms = menuMapper.selectMenuPermsByUserId(userId);
        Set<String> permsSet = new HashSet<>();
        for (String perm : perms) {
            if (StringUtils.isNotEmpty(perm)) {
                permsSet.addAll(Arrays.asList(perm.trim().split(",")));
            }
        }
        return permsSet;
    }

    /**
     * 根据角色ID查询权限
     *
     * @param roleId 角色ID
     * @return 权限列表
     */
    @Override
    public Set<String> selectMenuPermsByRoleId(Long roleId) {
        List<String> perms = menuMapper.selectMenuPermsByRoleId(roleId);
        Set<String> permsSet = new HashSet<>();
        for (String perm : perms) {
            if (StringUtils.isNotEmpty(perm)) {
                permsSet.addAll(Arrays.asList(perm.trim().split(",")));
            }
        }
        return permsSet;
    }

    @Override
    public List<SysMenuTreeDTO> selectMenuByUserId(Long userId, Long orgId, String endPoint) {
        List<SysMenuTreeDTO> menus;
        if (sysUserCommonService.isAdmin(userId)) {
            menus = menuMapper.selectMenuTreeAll(endPoint);
        } else {
            menus = menuMapper.selectMenuTreeByUserId(userId, orgId, endPoint);
        }
        return menus;
    }

    @Override
    public List<SysMenuTreeDTO> selectMenuTreeByUserIdRouter(Long userId, Long loginOrgId, String endPoint) {
        List<SysMenuTreeDTO> menus;
        if (sysUserCommonService.isAdmin(userId)) {
            menus = menuMapper.selectMenuTreeAllRouter(endPoint);
        } else {
            menus = menuMapper.selectMenuTreeByUserIdRouter(userId, loginOrgId, endPoint);
        }
        if (CollectionUtils.isEmpty(menus)) {
            return Lists.newArrayList();
        }
        //处理菜单数据权限
        dealMenuPermission(menus);
        int menuId = Math.toIntExact(menus.stream()
                .filter(item -> item.getParentId() == 0).findFirst().orElse(new SysMenuTreeDTO()).getMenuId());
        return getChildPerms(menus, menuId);
    }

    @Override
    public List<SysMenuTreeDTO> selectMenuTreeByUserIdRouterByGuest(String endPoint) {
        List<SysMenuTreeDTO> menus;
        menus = menuMapper.selectMenuTreeByUserIdRouterByGuest(endPoint);
        if (CollectionUtils.isEmpty(menus)) {
            return Lists.newArrayList();
        }
        //处理菜单数据权限
        dealMenuPermission(menus);
        int menuId = Math.toIntExact(menus.stream()
                .filter(item -> item.getParentId() == 0).findFirst().orElse(new SysMenuTreeDTO()).getMenuId());
        return getChildPerms(menus, menuId);
    }

    private void dealMenuPermission(List<SysMenuTreeDTO> menus) {
        if (!CollectionUtils.isEmpty(menus)) {
            for (SysMenuTreeDTO menu : menus) {
                if (!CollectionUtils.isEmpty(menu.getMenuPermissionDTOS())) {
                    List<SysMenuPermissionDTO> permissionDTOS = getMenuPermission(menu);
                    menu.setMenuPermissionDTOS(permissionDTOS);
                }
            }
        }
    }


    private List<SysMenuPermissionDTO> getMenuPermission(SysMenuTreeDTO menu) {
        List<SysMenuPermissionDTO> menuPermissionDTOS = new ArrayList<>();
        //根据菜单的数据权限key进行分组
        Map<String, List<SysMenuPermissionDTO>> listMap = menu.getMenuPermissionDTOS().stream().collect(Collectors.groupingBy(SysMenuPermissionDTO::getKeyCode));
        for (Map.Entry<String, List<SysMenuPermissionDTO>> entry : listMap.entrySet()) {
            List<SysMenuPermissionDTO> dtoList = listMap.get(entry.getKey());
            List<SelectOptionDTO> optionDTOS = new ArrayList<>();
            for (SysMenuPermissionDTO permissionDTO : dtoList) {
                if (StringUtils.isNotBlank(permissionDTO.getKeyValue())) {
                    optionDTOS.addAll(JSON.parseArray(permissionDTO.getKeyValue(), SelectOptionDTO.class));
                }
            }
            Map<String, String> keyValueMap = new HashMap<>();
            for (SelectOptionDTO dto : optionDTOS) {
                if (!keyValueMap.containsKey(dto.getValue())) {
                    keyValueMap.put(dto.getValue(), dto.getLabel());
                }
            }


            List<SelectOptionDTO> keyOptionDTO = new ArrayList<>();
            for (Map.Entry<String, String> value : keyValueMap.entrySet()) {
                SelectOptionDTO optionDTO = new SelectOptionDTO();
                optionDTO.setLabel(value.getValue());
                optionDTO.setValue(value.getKey());
                keyOptionDTO.add(optionDTO);
            }

            SysMenuPermissionDTO menuPermissionDTO = new SysMenuPermissionDTO();
            menuPermissionDTO.setKeyCode(entry.getKey());
            menuPermissionDTO.setSelectOptionDTOS(keyOptionDTO);
            menuPermissionDTOS.add(menuPermissionDTO);
        }
        return menuPermissionDTOS;
    }


    /**
     * 根据用户ID查询菜单
     *
     * @param userId 用户名称
     * @return 菜单列表
     */
    @Override
    public List<SysMenuTreeDTO> selectMenuTreeByUserId(Long userId, Long deptId, String systemType) {
        List<SysMenuTreeDTO> menus;
        if (SecurityUtils.isAdmin(userId)) {
            menus = menuMapper.selectMenuTreeAll(systemType);
        } else {
            menus = menuMapper.selectMenuTreeByUserId(userId, deptId, systemType);
        }
        if (CollectionUtils.isEmpty(menus)) {
            return Lists.newArrayList();
        }
        int menuId = Math.toIntExact(menus.stream()
                .filter(item -> item.getParentId() == 0).findFirst().orElse(new SysMenuTreeDTO()).getMenuId());
        return getChildPerms(menus, menuId);
    }

    @Override
    public List<SysMenuTreeDTO> getRouters(Long userId, Long deptId) {
        List<SysMenuTreeDTO> menus = selectMenuTreeByUserId(userId, deptId, MenuEndPointEnum.PC.name());
        if (CollectionUtils.isEmpty(menus)) {
            return Lists.newArrayList();
        }
        int menuId = Math.toIntExact(menus.stream()
                .filter(item -> item.getParentId() == 0).findFirst().orElse(new SysMenuTreeDTO()).getMenuId());
        return getChildPerms(menus, menuId);

    }

    /**
     * 根据角色ID查询菜单树信息
     *
     * @param roleId 角色ID
     * @return 选中菜单列表
     */
    @Override
    public List<Long> selectMenuListByRoleId(Long roleId) {
        SysRole role = roleMapper.selectRoleById(roleId);
        return menuMapper.selectMenuListByRoleId(roleId, role.isMenuCheckStrictly());
    }

    @Override
    public List<SysMenuTreeDTO> selectAppMenuTreeByUserId(Long userId, Long orgId, String endPoint) {
        List<SysMenuTreeDTO> menus;
        if (sysUserCommonService.isAdmin(userId)) {
            menus = this.menuMapper.selectAppMenuTreeAll(endPoint);
            if (!CollectionUtils.isEmpty(menus)) {
                for (SysMenuTreeDTO vo : menus) {
                    if (StringUtils.isEmpty(vo.getIconUrl())) {
                        vo.setIconUrl(configConstants.getIconUrl());
                    }
                }
            }
        } else {
            menus = this.menuMapper.selectAppMenuTreeByUserId(userId, orgId, endPoint);
            if (!CollectionUtils.isEmpty(menus)) {
                for (SysMenuTreeDTO vo : menus) {
                    if (StringUtils.isEmpty(vo.getIconUrl())) {
                        vo.setIconUrl(configConstants.getIconUrl());
                    }
                }
            }
        }
        if (CollectionUtils.isEmpty(menus)) {
            return Lists.newArrayList();
        }
        int menuId = Math.toIntExact(menus.stream()
                .filter(item -> item.getParentId() == 0).findFirst().orElse(new SysMenuTreeDTO()).getMenuId());
        return this.getChildPerms(menus, menuId);
    }

    @Override
    public List<RouterVo> buildMenusPc(List<SysMenuTreeDTO> menus, String host, String endPoint, Long rootId) {
        if (Objects.isNull(rootId)) {
            rootId = menuMapper.selectEndpointRootMenuId(endPoint);
            if (Objects.isNull(rootId)) {
                throw new ServiceException("终端【" + endPoint + "】的根目录不存在");
            }
        }
        List<RouterVo> routers = new LinkedList<>();
        for (SysMenuTreeDTO menu : menus) {
            if (!"inner_system".equals(menu.getSystemType())) {
                continue;
            }
            RouterVo router = new RouterVo();
            router.setMenuId(menu.getMenuId());
            router.setMenuPermissionDTOS(menu.getMenuPermissionDTOS());
            router.setHidden("1".equals(menu.getVisible()));
            router.setName(getRouteName(menu, rootId));


            router.setComponent(getComponent(menu, rootId));
            router.setQuery(menu.getQuery());

            String hostIp = null;
            if (StringUtils.isNotEmpty(host)) {
                hostIp = host.replaceAll("%3A", ":").replaceAll("%2F", "/")  //过滤URL 包含中文
                        .replaceAll("%3F", "?").replaceAll("%3D", "=").replaceAll(
                                "%26", "&");
            }

            String path = StringUtils.replaceEach(menu.getPath(), new String[]{"${host}"},
                    new String[]{hostIp});

            if (menu.getIsFrame().equals("0") && UserConstants.TYPE_MENU.equals(menu.getMenuType())) {
                router.setPath(path);
            } else {
                router.setPath(getRouterPath(menu, rootId));
            }

            router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), path));
            List<SysMenuTreeDTO> cMenus = menu.getChildren();
            if (!CollectionUtils.isEmpty(cMenus) && UserConstants.TYPE_DIR.equals(menu.getMenuType())) {
                router.setAlwaysShow(true);
                router.setRedirect("noRedirect");
                router.setChildren(buildMenusPc(cMenus, host, endPoint, rootId));
            } else if (isMenuFrame(menu, rootId)) {
                router.setMeta(null);
                List<RouterVo> childrenList = new ArrayList<RouterVo>();
                RouterVo children = new RouterVo();
                children.setMenuId(menu.getMenuId());
                children.setPath(menu.getPath());
                children.setComponent(menu.getComponent());
                children.setName(StringUtils.capitalize(menu.getPath()));
                children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
                children.setQuery(menu.getQuery());
                children.setMenuPermissionDTOS(menu.getMenuPermissionDTOS());
                childrenList.add(children);
                router.setChildren(childrenList);
            } else if (menu.getParentId().intValue() == rootId && isInnerLink(menu)) {
                router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
                router.setPath("/");
                List<RouterVo> childrenList = new ArrayList<RouterVo>();
                RouterVo children = new RouterVo();
                String routerPath = innerLinkReplaceEach(menu.getPath());
                children.setMenuId(menu.getMenuId());
                children.setPath(routerPath);
                children.setComponent(UserConstants.INNER_LINK);
                children.setName(StringUtils.capitalize(routerPath));
                children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath()));
                children.setMenuPermissionDTOS(menu.getMenuPermissionDTOS());
                childrenList.add(children);
                router.setChildren(childrenList);
            }
            routers.add(router);
        }
        return routers;
    }

    /**
     * 构建小程序所需要的菜单页面
     *
     * @param menus
     * @param
     * @return
     */
    @Override
    public List<RouterVo> buildMenusWeiXin(List<SysMenuTreeDTO> menus, String endPoint, Long rootId) {
        if (Objects.isNull(rootId)) {
            rootId = menuMapper.selectEndpointRootMenuId(endPoint);
            if (Objects.isNull(rootId)) {
                throw new ServiceException("终端【" + endPoint + "】的根目录不存在");
            }
        }
        List<RouterVo> routers = new LinkedList<>();
        for (SysMenuTreeDTO menu : menus) {
            RouterVo router = new RouterVo();
            router.setMenuPermissionDTOS(menu.getMenuPermissionDTOS());
            router.setHidden("1".equals(menu.getVisible()));
            router.setName(getRouteName(menu, rootId));
            router.setPath(getRouterPath(menu, rootId));
            router.setComponent(getComponent(menu, rootId));
            router.setQuery(menu.getQuery());
            router.setMenuId(menu.getMenuId());
            router.setOrderNum(menu.getOrderNum());
            String token = SecurityUtils.getToken();
            Claims claims;
            try {
                claims = JwtUtils.parseToken(token);
                if (isTourist(claims)) {
                    ArrayList<SysMenuPermissionDTO> sysMenuPermissionDTOS = new ArrayList<>();
                    SysMenuPermissionDTO sysMenuPermissionDTO = new SysMenuPermissionDTO();
                    sysMenuPermissionDTO.setKeyCode("DP_AIRPORT_CODE");
                    sysMenuPermissionDTO.setSelectOptionDTOS(SysUserConstants.GUEST_AIRPORT_LIST);
                    sysMenuPermissionDTOS.add(sysMenuPermissionDTO);
                    router.setMenuPermissionDTOS(sysMenuPermissionDTOS);
                }
            }catch (Exception e){
                log.error("解析token失败");
            }
            router.setMeta(new MetaVo(menu.getMenuName(), menu.getRemark(), menu.getIcon(), menu.getIconUrl(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
            List<SysMenuTreeDTO> cMenus = menu.getChildren();
            if (!CollectionUtils.isEmpty(cMenus) && UserConstants.TYPE_DIR.equals(menu.getMenuType())) {
                router.setAlwaysShow(true);
                router.setRedirect("noRedirect");
                router.setChildren(buildMenusWeiXin(cMenus, endPoint, rootId));
            } else if (isMenuFrame(menu, rootId)) {
                router.setMeta(null);
                List<RouterVo> childrenList = new ArrayList<>();
                RouterVo children = new RouterVo();
                children.setMenuPermissionDTOS(menu.getMenuPermissionDTOS());
                children.setPath(menu.getPath());
                children.setComponent(menu.getComponent());
                children.setName(StringUtils.capitalize(menu.getPath()));
                children.setMeta(new MetaVo(menu.getMenuName(), menu.getRemark(), menu.getIcon(), menu.getIconUrl(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
                children.setQuery(menu.getQuery());
                childrenList.add(children);
                router.setChildren(childrenList);
            } else if (menu.getParentId().intValue() == rootId && isInnerLink(menu)) {
                router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
                router.setPath("/");
                List<RouterVo> childrenList = new ArrayList<>();
                RouterVo children = new RouterVo();
                String routerPath = innerLinkReplaceEach(menu.getPath());
                children.setMenuPermissionDTOS(menu.getMenuPermissionDTOS());
                children.setPath(routerPath);
                children.setComponent(UserConstants.INNER_LINK);
                children.setName(StringUtils.capitalize(routerPath));
                children.setMeta(new MetaVo(menu.getMenuName(), menu.getRemark(), menu.getIcon(), menu.getIconUrl(), menu.getPath()));
                childrenList.add(children);
                router.setChildren(childrenList);
            }
            routers.add(router);
        }
        return routers;
    }


    private boolean isTourist(Claims claims) {
        String username = JwtUtils.getUserName(claims);
        String appName = JwtUtils.getAppName(claims);
        return StringUtils.isBlank(appName) && (StringUtils.isBlank(username) || username.contains("游客"));
    }

    /**
     * 构建前端路由所需要的菜单
     *
     * @param menus 菜单列表
     * @return 路由列表
     */
    @Override
    public List<RouterVo> buildMenus(List<SysMenuTreeDTO> menus, String endPoint, Long rootId) {
        if (Objects.isNull(rootId)) {
            rootId = menuMapper.selectEndpointRootMenuId(endPoint);
            if (Objects.isNull(rootId)) {
                throw new ServiceException("终端【" + endPoint + "】的根目录不存在");
            }
        }
        List<RouterVo> routers = new LinkedList<>();
        for (SysMenuTreeDTO menu : menus) {
            RouterVo router = new RouterVo();
            router.setHidden("1".equals(menu.getVisible()));
            router.setName(getRouteName(menu, rootId));
            router.setPath(getRouterPath(menu, rootId));
            router.setComponent(getComponent(menu, rootId));
            router.setQuery(menu.getQuery());
            router.setMeta(new MetaVo(menu.getMenuName(), menu.getRemark(), menu.getIcon(), menu.getIconUrl(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
            List<SysMenuTreeDTO> cMenus = menu.getChildren();
            if (!CollectionUtils.isEmpty(cMenus) && UserConstants.TYPE_DIR.equals(menu.getMenuType())) {
                router.setAlwaysShow(true);
                router.setRedirect("noRedirect");
                router.setChildren(buildMenus(cMenus, endPoint, rootId));
            } else if (isMenuFrame(menu, rootId)) {
                router.setMeta(null);
                List<RouterVo> childrenList = new ArrayList<>();
                RouterVo children = new RouterVo();
                children.setPath(menu.getPath());
                children.setComponent(menu.getComponent());
                children.setName(StringUtils.capitalize(menu.getPath()));
                children.setMeta(new MetaVo(menu.getMenuName(), menu.getRemark(), menu.getIcon(), menu.getIconUrl(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
                children.setQuery(menu.getQuery());
                childrenList.add(children);
                router.setChildren(childrenList);
            } else if (menu.getParentId().intValue() == rootId && isInnerLink(menu)) {
                router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
                router.setPath("/");
                List<RouterVo> childrenList = new ArrayList<>();
                RouterVo children = new RouterVo();
                String routerPath = innerLinkReplaceEach(menu.getPath());
                children.setPath(routerPath);
                children.setComponent(UserConstants.INNER_LINK);
                children.setName(StringUtils.capitalize(routerPath));
                children.setMeta(new MetaVo(menu.getMenuName(), menu.getRemark(), menu.getIcon(), menu.getIconUrl(), menu.getPath()));
                childrenList.add(children);
                router.setChildren(childrenList);
            }
            routers.add(router);
        }
        return routers;
    }

    /**
     * 构建前端所需要树结构
     *
     * @param menus 菜单列表
     * @return 树结构列表
     */
    @Override
    public List<SysMenuTreeDTO> buildMenuTree(List<SysMenuTreeDTO> menus) {
        List<SysMenuTreeDTO> returnList = new ArrayList<>();
        List<Long> tempList = menus.stream().map(SysMenuTreeDTO::getMenuId).collect(Collectors.toList());
        for (Iterator<SysMenuTreeDTO> iterator = menus.iterator(); iterator.hasNext(); ) {
            SysMenuTreeDTO menu = iterator.next();
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(menu.getParentId())) {
                TreeAdapterUtil.recursionFn(menus, menu, SysMenuTreeDTO.class);
                returnList.add(menu);
            }
        }
        if (returnList.isEmpty()) {
            returnList = menus;
        }
        return returnList;
    }

    /**
     * 构建前端所需要下拉树结构
     *
     * @param menus 菜单列表
     * @return 下拉树结构列表
     */
    @Override
    public List<TreeSelect> buildMenuTreeSelect(List<SysMenuTreeDTO> menus) {
        List<SysMenuTreeDTO> menuTrees = buildMenuTree(menus);
        return menuTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
    }

    /**
     * 根据菜单ID查询信息
     *
     * @param menuId 菜单ID
     * @return 菜单信息
     */
    @Override
    public SysMenuTreeDTO selectMenuById(Long menuId) {
        return menuMapper.selectMenuById(menuId);
    }

    /**
     * 是否存在菜单子节点
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    @Override
    public boolean hasChildByMenuId(Long menuId) {
        int result = menuMapper.hasChildByMenuId(menuId);
        return result > 0;
    }

    /**
     * 查询菜单使用数量
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    @Override
    public boolean checkMenuExistRole(Long menuId) {
        int result = roleMenuMapper.checkMenuExistRole(menuId);
        return result > 0;
    }

    /**
     * 新增保存菜单信息
     *
     * @param menu 菜单信息
     * @return 结果
     */
    @Override
    public int insertMenu(SysMenuTreeDTO menu) {
        return menuMapper.insertMenu(menu);
    }

    /**
     * 修改保存菜单信息
     *
     * @param menu 菜单信息
     * @return 结果
     */
    @Override
    public int updateMenu(SysMenuTreeDTO menu) {
        SysMenuTreeDTO oldMenu = menuMapper.selectMenuById(menu.getMenuId());
        int row = menuMapper.updateMenu(menu);
        //如果菜单状态由有效变为无效，则需要将子菜单变为无效。
        if (row > 0) {

            if (MenuStatus.OK.getCode().equals(oldMenu.getStatus()) &&
                    MenuStatus.DISABLE.getCode().equals(menu.getStatus())) {

                List<SysMenuTreeDTO> allChildlist = new ArrayList<>();
                allChildlist = getAllChildMenu(allChildlist, menu.getMenuId());
                System.out.println("获取子菜单------------" + JSON.toJSONString(allChildlist));
                if (!CollectionUtils.isEmpty(allChildlist)) {

                    for (SysMenuTreeDTO childMenu : allChildlist) {
                        childMenu.setStatus(MenuStatus.DISABLE.getCode());
                        menuMapper.updateMenu(childMenu);

                    }
                }
            }


        }
        return row;
    }

    @Override
    public List<SysMenuTreeDTO> getAllChildMenu(Long menuId) {
        List<SysMenuTreeDTO> allChildlist = new ArrayList<>();
        return getAllChildMenu(allChildlist, menuId);
    }

    @Override
    public List<SysMenuPermissionVO> getDataPermissions(SysUser sysUser) {

        return menuMapper.getDataPermissions(sysUser);
    }

    @Override
    public List<SysMenuPermissionVO> getDataPermissionsAll(SysUser sysUser) {

        return menuMapper.getDataPermissionsAll(sysUser);
    }

    @Override
    public void saveButtonPermissions(Long parentId, String prefix) {
        if (parentId == null || StringUtils.isBlank(prefix)) {
            throw new ServiceException("parentId或者prefix为空");
        }
        Map<String, String> buttonPermissions = new HashMap<>();
        buttonPermissions.put("list", "列表");
        buttonPermissions.put("query", "详情");
        buttonPermissions.put("add", "新增");
        buttonPermissions.put("edit", "修改");
        buttonPermissions.put("remove", "删除");
        buttonPermissions.put("export", "导出");
        int count = 0;
        for (Map.Entry<String, String> entry : buttonPermissions.entrySet()) {
            SysMenuTreeDTO sysMenuTreeDTO = new SysMenuTreeDTO();
            sysMenuTreeDTO.setEndPoint("PC");
            sysMenuTreeDTO.setMenuName(entry.getValue());
            sysMenuTreeDTO.setParentId(parentId);
            sysMenuTreeDTO.setOrderNum(count);
            sysMenuTreeDTO.setIsFrame("1");
            sysMenuTreeDTO.setIsCache("0");
            sysMenuTreeDTO.setMenuType("F");
            sysMenuTreeDTO.setVisible("0");
            sysMenuTreeDTO.setStatus("0");
            sysMenuTreeDTO.setPerms(prefix + ":" + entry.getKey());
            sysMenuTreeDTO.setIcon("#");
            sysMenuTreeDTO.setSystemType("inner_system");
            sysMenuTreeDTO.setIsDelete("N");
            sysMenuTreeDTO.setCreateBy("admin");
            sysMenuTreeDTO.setCreateTime(new Date());
            sysMenuTreeDTO.setRemark("系统批量新增");
            sysMenuTreeDTO.setMenuFlag("1");
            menuMapper.insertMenu(sysMenuTreeDTO);
        }
    }

    private List<SysMenuTreeDTO> getAllChildMenu(List<SysMenuTreeDTO> list, Long menuId) {
        List<SysMenuTreeDTO> childList = menuMapper.queryChildByMenuId(menuId);
        if (!CollectionUtils.isEmpty(childList)) {
            list.addAll(childList);

            for (SysMenuTreeDTO tChild : childList) {
                getAllChildMenu(list, tChild.getMenuId());
            }
        }

        return list;
    }


    /**
     * 删除菜单管理信息
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    @Override
    public int deleteMenuById(Long menuId) {
        return menuMapper.deleteMenuById(menuId);
    }

    /**
     * 校验菜单名称是否唯一
     *
     * @param menu 菜单信息
     * @return 结果
     */
    @Override
    public boolean checkMenuNameUnique(SysMenuTreeDTO menu) {
        Long menuId = StringUtils.isNull(menu.getMenuId()) ? -1L : menu.getMenuId();
        SysMenuTreeDTO info = menuMapper.checkMenuNameUnique(menu.getMenuName(), menu.getParentId(), menu.getSystemType());
        if (StringUtils.isNotNull(info) && info.getMenuId().longValue() != menuId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    @Override
    public boolean checkMenuPathUnique(SysMenuTreeDTO menu) {
        Long menuId = StringUtils.isNull(menu.getMenuId()) ? -1L : menu.getMenuId();
        if (!SysUserConstants.MENU_TYPE_F.equals(menu.getMenuType())) {
            SysMenuTreeDTO info = menuMapper.checkMenuPathUnique(menu.getPath());
            if (StringUtils.isNotNull(info) && info.getMenuId().longValue() != menuId.longValue() ) {
                if (StringUtils.isNotEmpty(menu.getEndPoint())){
                    if (menu.getEndPoint().equals(info.getEndPoint())){
                        return UserConstants.NOT_UNIQUE;
                    }
                }else {
                    return UserConstants.NOT_UNIQUE;
                }
            }
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 获取路由名称
     *
     * @param menu   菜单信息
     * @param rootId
     * @return 路由名称
     */
    public String getRouteName(SysMenuTreeDTO menu, Long rootId) {
        String routerName = StringUtils.capitalize(menu.getPath());
        // 非外链并且是一级目录（类型为目录）
        if (isMenuFrame(menu, rootId)) {
            routerName = StringUtils.EMPTY;
        }
        return routerName;
    }

    /**
     * 获取路由地址
     *
     * @param menu   菜单信息
     * @param rootId
     * @return 路由地址
     */
    public String getRouterPath(SysMenuTreeDTO menu, Long rootId) {
        String routerPath = menu.getPath();
        // 内链打开外网方式
        if (menu.getParentId().intValue() != rootId && isInnerLink(menu)) {
            routerPath = innerLinkReplaceEach(routerPath);
        }
        // 非外链并且是一级目录（类型为目录）
        if (rootId == menu.getParentId().intValue() && UserConstants.TYPE_DIR.equals(menu.getMenuType())
                && UserConstants.NO_FRAME.equals(menu.getIsFrame())) {
            routerPath = "/" + menu.getPath();
        }
        // 非外链并且是一级目录（类型为菜单）
        else if (isMenuFrame(menu, rootId)) {
            routerPath = "/";
        }
        return routerPath;
    }

    /**
     * 获取组件信息
     *
     * @param menu   菜单信息
     * @param rootId
     * @return 组件信息
     */
    public String getComponent(SysMenuTreeDTO menu, Long rootId) {
        String component = UserConstants.LAYOUT;
        if (StringUtils.isNotEmpty(menu.getComponent()) && !isMenuFrame(menu, rootId)) {
            component = menu.getComponent();
        } else if (StringUtils.isEmpty(menu.getComponent()) && menu.getParentId().intValue() != rootId && isInnerLink(menu)) {
            component = UserConstants.INNER_LINK;
        } else if (StringUtils.isEmpty(menu.getComponent()) && isParentView(menu, rootId)) {
            component = UserConstants.PARENT_VIEW;
        }
        return component;
    }

    /**
     * 是否为菜单内部跳转
     *
     * @param menu 菜单信息
     * @return 结果
     */
    public boolean isMenuFrame(SysMenuTreeDTO menu, Long rootId) {
        return menu.getParentId().intValue() == rootId && UserConstants.TYPE_MENU.equals(menu.getMenuType())
                && menu.getIsFrame().equals(UserConstants.NO_FRAME);
    }

    /**
     * 是否为内链组件
     *
     * @param menu 菜单信息
     * @return 结果
     */
    public boolean isInnerLink(SysMenuTreeDTO menu) {
        return menu.getIsFrame().equals(UserConstants.NO_FRAME) && StringUtils.ishttp(menu.getPath());
    }

    /**
     * 是否为parent_view组件
     *
     * @param menu   菜单信息
     * @param rootId
     * @return 结果
     */
    public boolean isParentView(SysMenuTreeDTO menu, Long rootId) {
        return menu.getParentId().intValue() != rootId && UserConstants.TYPE_DIR.equals(menu.getMenuType());
    }

    /**
     * 根据父节点的ID获取所有子节点
     *
     * @param list     分类表
     * @param parentId 传入的父节点ID
     * @return String
     */
    public List<SysMenuTreeDTO> getChildPerms(List<SysMenuTreeDTO> list, int parentId) {
        List<SysMenuTreeDTO> returnList = new ArrayList<>();
        for (Iterator<SysMenuTreeDTO> iterator = list.iterator(); iterator.hasNext(); ) {
            SysMenuTreeDTO t = iterator.next();
            // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点
            if (t.getParentId() == parentId) {
                TreeAdapterUtil.recursionFn(list, t, SysMenuTreeDTO.class);
                returnList.add(t);
            }
        }
        return returnList;
    }

    /**
     * 得到子节点列表
     */
    private List<SysMenuTreeDTO> getChildList(List<SysMenuTreeDTO> list, SysMenuTreeDTO t) {
        List<SysMenuTreeDTO> tlist = new ArrayList<>();
        Iterator<SysMenuTreeDTO> it = list.iterator();
        while (it.hasNext()) {
            SysMenuTreeDTO n = it.next();
            if (n.getParentId().longValue() == t.getMenuId().longValue()) {
                tlist.add(n);
            }
        }
        return tlist;
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<SysMenuTreeDTO> list, SysMenuTreeDTO t) {
        return getChildList(list, t).size() > 0;
    }

    /**
     * 内链域名特殊字符替换
     *
     * @return
     */
    public String innerLinkReplaceEach(String path) {
        return StringUtils.replaceEach(path, new String[]{Constants.HTTP, Constants.HTTPS, Constants.WWW, ".",
                        "/%23/", "/#/", "?", "=", "&", "${host}"},
                new String[]{"", "", "", "/", "/", "/", "", "/", "/", "host"});
    }
}
